home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-07-28 | 11.4 KB | 489 lines | [TEXT/MPS ] |
- /*
- File: TThread.cp
-
- Contains: xxx put contents here xxx
-
- Written by: Tim Harnett
-
- Copyright: © 1994 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <13> 2/7/95 TMH added userinterrupt stuff
- <12> 2/6/95 TMH redid CEventQueue using CLinkedList
- <11> 12/20/94 TMH fix bug so we don't overflow event queue
- <10> 12/12/94 TMH added of thread events
- <9> 11/17/94 TMH fix to TWakeupThread::Busy
- <8> 11/11/94 TMH fixed TWakeupThread::Busy() to look at IO state
- <7> 11/10/94 TMH use StopForIO
- <6> 11/8/94 TMH added fIdentifierTag
- <5> 10/28/94 TMH added gAppTaskRef and StartThreadFromCompletionRoutine
- <4> 10/26/94 TMH added GetThreadA5
- <3> 10/25/94 TMH added TWakeupThread
- <2> 10/6/94 TMH added TApplicationThread
- <1> 9/21/94 TMH seperated from Application.cp
- 9/21/94 TMH xxx put comment here xxx
-
- To Do:
- */
-
- #ifndef __STRING__
- #include <String.h>
- #endif
-
- #ifndef __TYPES__
- #include <Types.h>
- #endif
-
- #ifndef __Debug__
- #include "Debug.h"
- #endif
-
- #ifndef __UFAILURE__
- #include "UFailure.h"
- #endif
-
- #ifndef __Globals__
- #include "Globals.h"
- #endif
-
- #ifndef __TThread__
- #include "TThread.h"
- #endif
-
- #ifndef __Application__
- #include "Application.h"
- #endif
-
-
-
- ThreadTaskRef TCooperativeThread::gAppTaskRef = 0;
- unsigned long TCooperativeThread::gDebugCallCount = 0; // this is for debugging, remove it later
- #pragma segment TThread
-
- //-----------------------------------------------
- // T C o o p e r a t i v e T h r e a d
- //-----------------------------------------------
-
-
- //-------------------------------------------------------------------------------------
- TCooperativeThread::TCooperativeThread()
- {
- fThreadID = 0;
- fOutParam = 0;
- fWNESleep = kSleepTime;
-
- fSavedTopHandler = 0;
- fA5 = ::SetCurrentA5();
-
- fIdentifierTag = 0;
-
- fThreadIOState = sThreadIOIdle;
-
-
- fEventQueue = 0;
-
- fUserInterrupt = 0;
- }
-
-
-
- //-------------------------------------------------------------------------------------
- TCooperativeThread::~TCooperativeThread()
- {
- if( fEventQueue != 0 )
- DisposePtr((Ptr)fEventQueue);
-
- ASSERT(this->GetThreadState() == kStoppedThreadState );
- ASSERT(fThreadID != 0 );
-
- OSErr osErr = DisposeThread(fThreadID,0,false);
- ASSERTNOERR(osErr);
-
- }
-
-
- //-------------------------------------------------------------------------------------
- void TCooperativeThread::ICooperativeThread(OSType tag, Size stackSize,ThreadOptions createOptions,long wneSleep)
- {
- // filter out our extensions
- ThreadOptions threadMgrOptions = createOptions & (kNewSuspend+kUsePremadeThread+kCreateIfNeeded+kFPUNotNeeded+kExactMatchThread);
-
-
- OSErr osErr = NewThread(kCooperativeThread,(ThreadEntryProcPtr)TCooperativeThread::__ThreadMain,this,stackSize,createOptions,&fOutParam,&fThreadID);
- ASSERTNOERR(osErr);
- FailOSErr(osErr);
-
- fWNESleep = wneSleep;
-
- SetThreadSwitcher ( fThreadID, (ThreadSwitchProcPtr) SwitchInProc, (void*) this, true );
- SetThreadSwitcher ( fThreadID, (ThreadSwitchProcPtr) SwitchOutProc, (void*) this, false );
-
- fIdentifierTag = tag;
-
- if( createOptions & kNeedEventQueue ) {
- fEventQueue = new CThreadEventQueue;
- }
-
- }
-
-
- //-------------------------------------------------------------------------------------
- pascal void* TCooperativeThread::__ThreadMain(void* inParam)
- {
- TCooperativeThread* thisThread = (TCooperativeThread*)inParam;
- return thisThread->ThreadMain(); // polymorphic dispatch
-
- // If you are really paranoid a failure handler should go here.
- // For now we assume the subclass does this. Live Dangerously?
-
- }
-
-
- //-------------------------------------------------------------------------------------
- pascal void TCooperativeThread::SwitchInProc ( ThreadID /* threadBeingSwitched */, void* switchProcParam )
- {
- TCooperativeThread* thisThread = ( TCooperativeThread *) switchProcParam;
- ASSERT(thisThread);
-
- if ( thisThread ) {
-
- unsigned long savedA5 = ::SetA5( thisThread->fA5 );
-
- gTopHandler = (FailInfoPtr) thisThread->fSavedTopHandler;
-
- gCurrentThread = thisThread;
-
- ::SetA5 ( savedA5 );
-
- }
-
- }
-
-
-
- //-------------------------------------------------------------------------------------
- pascal void TCooperativeThread::SwitchOutProc ( ThreadID /* threadBeingSwitched */, void* switchProcParam )
- {
- TCooperativeThread* thisThread = ( TCooperativeThread *) switchProcParam;
- ASSERT(thisThread);
-
- if ( thisThread ) {
-
- thisThread->fSavedTopHandler = gTopHandler;
-
- gTopHandler = 0;
-
- }
- }
-
-
- //-------------------------------------------------------------------------------------
- void TCooperativeThread::Yield(TCooperativeThread* threadToRun)
- {
- OSErr osErr;
-
- if( threadToRun == 0 )
- osErr = YieldToAnyThread();
- else
- osErr = YieldToThread(threadToRun->fThreadID);
-
-
- ASSERTNOERR(osErr);
-
- }
-
-
-
- //-------------------------------------------------------------------------------------
- ThreadState TCooperativeThread::GetThreadState()
- {
- ThreadState threadState;
- OSErr osErr = ::GetThreadState(fThreadID,&threadState);
- ASSERTNOERR(osErr);
-
- if( fThreadIOState == sThreadStoppedForIO )
- threadState = (ThreadState) fThreadIOState; // when stopped for IO return sThreadStoppedForIO
-
-
- return threadState;
-
- }
-
-
- //-------------------------------------------------------------------------------------
- void TCooperativeThread::StopForIO()
- {
- fThreadIOState = sThreadStoppedForIO;
-
- OSErr osErr = ::SetThreadState(fThreadID, kStoppedThreadState, kApplicationThreadID);
- ASSERTNOERR(osErr);
-
- fThreadIOState = sThreadIOIdle;
-
- }
-
-
- //-------------------------------------------------------------------------------------
- OSErr TCooperativeThread::QueueEvent(CThreadEvent& threadEvent)
- {
- OSErr osErr = 0; //•• no errors yet
-
- ASSERT(fEventQueue!=0);
- ASSERT(fEventQueue->EventCount() < kMaxThreadEvents);
-
- if( (fEventQueue != 0) && (fEventQueue->EventCount() < kMaxThreadEvents) ) {
-
- fEventQueue->Insert(threadEvent);
- if( this->IsStopped() ) {
- OSErr err = this->StartThread();
- gApplication->SetWNESleepTime(this->GetWNESleep()); //••• NEED to work on setting approriate sleep time.
- }
-
- }
-
- return osErr;
-
- }
-
-
- //-------------------------------------------------------------------------------------
- OSErr TCooperativeThread::PostEvent(CThreadEvent& theEvent, Boolean allowDuplicate)
- {
- CThreadEventIterator eventIter(fEventQueue);
- Boolean queueIt = true;
-
- OSErr osErr = 0;
-
- CThreadEvent* threadEvent;
- for( threadEvent = eventIter.FirstEvent(); eventIter.More(); threadEvent = eventIter.NextEvent() ) {
-
- if( threadEvent->EventID() == theEvent.EventID() ) {
-
- if( !allowDuplicate )
- queueIt = false;
-
- break;
- }
-
- }
-
- if( queueIt )
- osErr = this->QueueEvent(theEvent);
- return osErr;
-
-
- }
-
-
- //-------------------------------------------------------------------------------------
- OSErr TCooperativeThread::PostEvent(long eventID,long eventData0, Boolean allowDuplicate)
- {
- CThreadEvent threadEvent(eventID,eventData0);
- return this->PostEvent(threadEvent,allowDuplicate);
-
- }
-
-
- //-------------------------------------------------------------------------------------
- CThreadEvent* TCooperativeThread::WaitNextEvent()
- {
- OSErr err;
-
- while( !this->EventAvail() )
- {
- err = this->StopThread();
- }
-
- return this->GetNextEvent();
-
- }
-
-
-
- //-------------------------------------------------------------------------------------
- CThreadEvent* TCooperativeThread::EventAvail()
- {
- static CThreadEvent gNextEvent;
-
- ASSERT(fEventQueue!=0);
-
- if( (fEventQueue != 0) && (fEventQueue->EventCount() != 0) ) {
- fEventQueue->CopyNextEvent(gNextEvent); // copy it but do not remove it from queue
- return &gNextEvent;
- }
-
- return 0;
-
- }
-
-
- //-------------------------------------------------------------------------------------
- CThreadEvent* TCooperativeThread::GetNextEvent()
- {
- static CThreadEvent gCurrentEvent;
-
- ASSERT(fEventQueue!=0);
- if( fEventQueue != 0 )
- fEventQueue->Remove(gCurrentEvent);
-
- return &gCurrentEvent;
- }
-
-
-
- //---------------------------------------
- // C T h r e a d E v e n t Q u e u e
- //----------------------------------------
-
- CThreadEventQueue::CThreadEventQueue()
- {
- memset(&fEventBufs,0,(kMaxThreadEvents*sizeof(CThreadEvent)));
-
- // load up the avail able list
-
- for(int i=0;i<kMaxThreadEvents;i++)
- fAvail.LinkTail(&fEventBufs[i]);
-
- }
-
-
- //-------------------------------------------------------------------------------------
- void CThreadEventQueue::Insert(CThreadEvent& threadEvent)
- {
- ASSERTPRINT(fEvents.Count() != kMaxThreadEvents,("Overflowed thread eventqueue Event Dropped\n"));
-
- if( fEvents.Count() != kMaxThreadEvents ) {
-
- CThreadEvent* event = (CThreadEvent*) fAvail.UnlinkHead();
-
- BlockMoveData(&threadEvent,event,sizeof(CThreadEvent));
-
- fEvents.LinkTail(event);
-
- }
-
- }
-
- //-------------------------------------------------------------------------------------
- void CThreadEventQueue::Remove(CThreadEvent& threadEvent)
- {
- if( fEvents.Count() != 0 ) {
-
- CThreadEvent* event = (CThreadEvent*) fEvents.UnlinkHead();
- BlockMoveData(event,&threadEvent,sizeof(CThreadEvent));
- fAvail.LinkTail(event);
-
- } else {
- memset(&threadEvent,0,sizeof(CThreadEvent)) ; // make it null event
-
- }
-
-
- }
-
- //-------------------------------------------------------------------------------------
- void CThreadEventQueue::FlushEvents(long eventID)
- {
-
- CLinkedListIterator iter(&fEvents);
- CThreadEvent* threadEvent;
- for(threadEvent = (CThreadEvent*)iter.FirstItem(); iter.More(); threadEvent = (CThreadEvent*)iter.NextItem() ) {
-
- if( eventID == 'all ' || threadEvent->EventID() == eventID ) {
-
- iter.UnlinkCurrentItem();
- fAvail.LinkTail(threadEvent);
-
- }
-
-
- }
-
- }
-
-
-
- //-------------------------------------------------------------------------------------
- void CThreadEventQueue::CopyNextEvent(CThreadEvent& threadEvent)
- {
- CThreadEvent* event = (CThreadEvent*) fEvents.Head();
-
- if( event != 0 )
- BlockMoveData(event,&threadEvent,sizeof(CThreadEvent));
-
- }
-
- //-----------------------------------------------
- // T A p p l i c a t i o n T h r e a d
- //-----------------------------------------------
-
-
- //-------------------------------------------------------------------------------------
- void* TApplicationThread::ThreadMain()
- {
- ASSERTPRINT(false,("What the hell ya doin here?\n"));
-
- return 0;
- }
-
- //-------------------------------------------------------------------------------------
- void TApplicationThread::IApplicationThread()
- {
-
- // A little be sleazy. We don't call ICooperativeThread cause
- // the application thread is automagically created by the thread
- // manager. But we do need to switch it in and out.
-
- fIdentifierTag = 'main';
-
- fWNESleep = kSleepTime;
- fThreadID = kApplicationThreadID;
- fSavedTopHandler = gTopHandler;
-
-
- SetThreadSwitcher ( fThreadID, (ThreadSwitchProcPtr) SwitchInProc, (void*) this, true );
- SetThreadSwitcher ( fThreadID, (ThreadSwitchProcPtr) SwitchOutProc, (void*) this, false );
-
- FailOSErr( GetThreadCurrentTaskRef(&gAppTaskRef) );
- }
-
-
-
- //-----------------------------
- // T W a k e u p T h r e a d
- //----------------------------
-
- //---------------------------------------------------------------
- TWakeupThread::TWakeupThread()
- {
- fThreadToWake = 0;
- }
-
- //---------------------------------------------------------------
- void* TWakeupThread::ThreadMain()
- {
- while(true) {
-
- ASSERT(fThreadToWake!=0);
- OSErr err = fThreadToWake->StartThread();
-
- gDebugCallCount++;
-
- err = this->StopThread();
-
- }
-
- return this;
- }
-
- //---------------------------------------------------------------
- void TWakeupThread::IWakeupThread()
- {
- // These threads need very little stack.
-
- this->ICooperativeThread('wake', kWakeupThreadStacksize,kNewSuspend);
-
- }
-
-